package ApplicationStart.Controller;

import ApplicationStart.Domain.*;
import ApplicationStart.SparkService.KMeans;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;

@Api(value = "测试Print方法", produces = "新手API", consumes = "Tester",
        protocols = "http", description = "这个是用来测试API功能的入口")
@RestController("Hello")
public class HelloController {


    @Autowired
    public HelloController(UserRepository userRepository, UserCreditRepository userCreditRepository, ReaderRepository readerRepository, KMeans kMeans) {
        this.userRepository = userRepository;
        this.userCreditRepository = userCreditRepository;
        this.readerRepository = readerRepository;
        this.kMeans = kMeans;
    }

    @ApiOperation(value="获取用户列表", notes="输入相关内容打印相关内容出来，默认无参数打印 'Hello World'",
            responseContainer = "List", response = String.class, protocols = "http", httpMethod = "GET")
    @RequestMapping("/print/{context}")
    public String printHelloWorld(@ApiParam(value = "需要打印的内容") @PathVariable String context){
        if (context != null && !context.isEmpty()) return context;
        return "Hello World";
    }

    @ApiOperation(value="redirct:/print", notes="调用转发到/print",
            responseContainer = "List", response = String.class, protocols = "http", httpMethod = "GET")
    @RequestMapping("/getApi/{context}")
    public void getApi(@ApiParam(value = "需要打印的内容", type = "String") @PathVariable String context, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
        if (context == null || context.isEmpty())
            context = "Api Version";
        httpServletRequest.getRequestDispatcher("/print/" + context).forward(httpServletRequest, httpServletResponse);
    }

    @ApiOperation(value="获取请求Person", notes="格式化Json",httpMethod = "PUT", response = PersonScala.class)
    @RequestMapping("/setPerson")
    public PersonScala getPerson(@ApiParam String name, @ApiParam Short age){
        return new PersonScala(name, age);
    }

    private final UserRepository userRepository;

    private final UserCreditRepository userCreditRepository;

    @RequestMapping("/User/{id}")
    @ApiOperation(httpMethod = "GET", value="获取用户信息")
    @ApiResponse(code=200, message = "success")
    public UserBean UserInfoById(@PathVariable Integer id){
        return this.userRepository.findById(id);
    }

    @RequestMapping("/UserCredit/{id}")
    @ApiOperation(httpMethod = "GET", value="通过债权Id获取用户债权信息")
    @ApiResponse(code=200, message = "success")
    public UserCredit UserCreditInfoById(@PathVariable Integer id) {
        return this.userCreditRepository.findOne(id);
    }

    @RequestMapping("/UserCreditByUserId/{id}")
    @ApiOperation(httpMethod = "GET", value="通过用户Id获取用户债权信息")
    @ApiResponse(code=200, message = "success")
    public List<UserCredit> UserCreditInfoByUserId(@PathVariable Integer id) {
        return this.userCreditRepository.findAllByUserId(id);
    }

    @RequestMapping("/addCredit")
    @ApiOperation(httpMethod = "POST", value="添加用户债权记录")
    @ApiResponse(code = 200, message = "success")
    public String addUserCredit(@Valid UserCredit userCredit, BindingResult bindingResult){
        if (bindingResult.hasErrors()) {
            return bindingResult.toString();
        }
        return userCreditRepository.save(userCredit).getUserId().toString();
    }

    private final ReaderRepository readerRepository;

    @RequestMapping("/addReader")
    @ApiOperation(httpMethod = "POST", value="添加权限用户")
    @ApiResponse(code = 200, message = "success")
    public String addReader(@Valid ReaderBean readerBean, BindingResult bindingResult){
        if (bindingResult.hasErrors()) {
            return bindingResult.toString();
        }
        return readerRepository.save(readerBean).getUsername();
    }

    private final KMeans kMeans;

    @RequestMapping("/CreditCount")
    @ApiOperation(httpMethod = "GET", value="获取用户债权记录条数")
    @ApiResponse(code=200, message = "success")
    public Long creditCount() {
        return kMeans.countRecode(kMeans.SQLRequestByIds(1L, 200L));
    }

    @RequestMapping("/ageDistribute")
    @ApiOperation(httpMethod = "GET", value="用户年龄分布情况")
    @ApiResponse(code=200, message = "success")
    public List<Map<String, Integer>> ageDistribute(){
        Integer count = 20;
        List<Integer> ages = kMeans.ageDistribute();
        Integer[] maxAndMin = getMaxAndMin(ages, new Integer[]{0, 0}, 0);
        Map<String, List<Integer>> groups = groupByCount(ages, maxAndMin, count);
        List<Map<String, Integer>> ageLists = new ArrayList<>();
        for(Map.Entry<String, List<Integer>> entry : groups.entrySet()){
            Map<String, Integer> countMap = new TreeMap<>();
            countMap.put("count", entry.getValue().size());
            countMap.put("label", Integer.parseInt(entry.getKey())); //label -- xAsa
            ageLists.add(countMap);
        }
        ageLists.sort(Comparator.comparingInt(o -> o.get("label")));
        return ageLists;
    }

    /**
     * 1. 实时在线请求的地址，进行获取得到高并发
     * 2. 获得实时的数据信息, from 来自于高并发数据库 redis
     * @return 地图统计数据
     */
    public List<Map<String, Object>> onlineUserStatic(){
        return null;
    }

    private Map<String , List<Integer>> groupByCount(List<Integer> datas, Integer[] maxAndMin, Integer count){
        Double utils = 0.0 + maxAndMin[0] - maxAndMin[1];
        Integer[] uuidRange = new Integer[count];
        Map<String, List<Integer>> map = new LinkedHashMap<>();
        for (int i = 0; i < count; i ++) {
            uuidRange[i] = (int) (maxAndMin[1] + utils / count * (i + 1));
        }
        for (Integer data : datas) {
            int address = 0;
            for (int i = 0; i < count; i++){
                if (data <= uuidRange[i]){
                    address = i;
                    break;
                }
            }
            String key = uuidRange[address].toString();
            if (map.containsKey(key)){
                map.get(key).add(data);
            }else{
                map.put(key, new ArrayList<>());
            }
        }
        return map;
    }

    private Integer[] getMaxAndMin(List<Integer> list, Integer[] init, int index){
        if (list.size() == index || list.size() == 0) return init;
        switch (index){
            case 1 :
                init = new Integer[]{list.get(1), list.get(1)};
                break;
            default:
                init[0] = Math.max(init[0], list.get(index));
                init[1] = Math.min(init[1], list.get(index));
        }
        return getMaxAndMin(list, init, index + 1);
    }
}